package com.sojson.project.pay.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.sojson.base.impl.BaseOrder;
import com.sojson.config.exception.bean.Status;
import com.sojson.constant.Constant;
import com.sojson.constant.ConstantCache;
import com.sojson.constant.ConstantMessageSystemTemplate;
import com.sojson.constant.Lock;
import com.sojson.enums.EBalanceCount;
import com.sojson.enums.EBalanceTotalType;
import com.sojson.enums.EBalanceType;
import com.sojson.enums.EEarnestMoneyStatus;
import com.sojson.enums.EMessageSystemType;
import com.sojson.enums.EOrderDepositStatus;
import com.sojson.enums.EOrderStatusHotel;
import com.sojson.enums.ETransferRecordStatus;
import com.sojson.enums.ETransferRecordType;
import com.sojson.enums.core.EGeneralYesNo;
import com.sojson.enums.core.EModuleNo;
import com.sojson.enums.core.EOrderCloseType;
import com.sojson.enums.core.EOrderHotelCloseType;
import com.sojson.enums.core.EOrderStatus;
import com.sojson.enums.core.EPayStatus;
import com.sojson.enums.core.EPayType;
import com.sojson.enums.core.ERefundsStatus;
import com.sojson.enums.core.EUserCouponStatus;
import com.sojson.project.dao.OrderDepositDao;
import com.sojson.project.dao.TransferRecordDao;
import com.sojson.project.dao.UserCouponDao;
import com.sojson.project.entity.bo.PayResponse;
import com.sojson.project.entity.po.BalanceLog;
import com.sojson.project.entity.po.GoodSpecs;
import com.sojson.project.entity.po.HotelOrder;
import com.sojson.project.entity.po.HotelOrderRoom;
import com.sojson.project.entity.po.MessageSystem;
import com.sojson.project.entity.po.Order;
import com.sojson.project.entity.po.OrderDeposit;
import com.sojson.project.entity.po.OrderGoods;
import com.sojson.project.entity.po.TransferRecord;
import com.sojson.project.entity.po.UserCoupon;
import com.sojson.project.entity.vo.HotelOrderVo;
import com.sojson.project.entity.vo.WithdrawDepositVo;
import com.sojson.project.pay.service.PayService;
import com.sojson.project.service.BalanceLogService;
import com.sojson.project.service.GoodSpecsService;
import com.sojson.project.service.HotelOrderRoomService;
import com.sojson.project.service.HotelOrderService;
import com.sojson.project.service.MessageSystemService;
import com.sojson.project.service.OrderDepositService;
import com.sojson.project.service.OrderGoodsService;
import com.sojson.project.service.OrderService;
import com.sojson.project.sys.user.dao.UserDao;
import com.sojson.project.sys.user.entity.po.User;
import com.sojson.util.ArithUtil;
import com.sojson.util.DateUtil;
import com.sojson.util.ExpUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.SystemParamUtil;
import com.sojson.util.id.IdUtil;
import com.sojson.util.pay.ali.AliUtil;
import com.sojson.util.pay.wx.WxPayUtil;
import com.sojson.util.pay.wx.bean.WxResponseV2;
import com.sojson.util.token.TokenUtil;

/**
 * 支付Service实现类
 * 
 * @author liu
 * @date 2021-03-24
 */
@Service
public class PayServiceImpl implements PayService {

    @Lazy
    @Autowired
    private PayServiceImpl payService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderGoodsService orderGoodsService;
    @Autowired
    private MessageSystemService messageSystemService;
    @Autowired
    private OrderDepositService orderDepositService;
    @Autowired
    private HotelOrderService hotelOrderService;
    @Autowired
    private HotelOrderRoomService hotelOrderRoomService;
    @Autowired
    private BalanceLogService balanceLogService;
    @Autowired
    private GoodSpecsService goodSpecsService;
    @Resource
    private UserCouponDao userCouponDao;
    @Resource
    private UserDao userDao;
    @Resource
    private OrderDepositDao orderDepositDao;
    @Resource
    private TransferRecordDao transferRecordDao;

    /**
     * 商城购物车调起支付
     * 
     * @param nos
     * @return
     * @throws Exception 
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public PayResponse goodsShop(String[] nos) throws Exception {
        // 查看订单是否存在
        List<Order> findByShopNo = orderService.findByNoArr(nos);
        int size = findByShopNo.size();
        if (StringUtil.isBlankObject(findByShopNo) || size < 1) {
            ExpUtil.throwEx("订单不存在！");
        }
        for (Order order : findByShopNo) {
            if ((order.getCreatedAt().getTime() + Constant.ORDER_PAY_TIME) < DateUtil.nowLong()) {
                ExpUtil.throwEx("订单支付超时！");
            }
            if (EOrderStatus.PAYMENT_NO.getCode() != order.getStatus()) {
                ExpUtil.throwEx("订单状态不是待付款！");
            }
        }

        PayResponse res = new PayResponse();
        // 是否是购物车支付
        if (size > 1) {
            res.setIsShop(true);
            res.setOrders(payService.goodsShopGo(findByShopNo));
        } else {
            res.setIsShop(false);
            res.setOrder(payService.goodsGo(findByShopNo.get(0)));
        }
        return res;
    }

    /**
     * 商城调起支付
     * 
     * @param order
     * @return
     * @throws Exception 
     */
    @Transactional(rollbackFor = Throwable.class)
    public Order goodsGo(Order order) throws Exception {
        String byMap = SystemParamUtil.getStr(ConstantCache.WEB_NAME);
        order.setBaseTitle(byMap + "商城购物车");

        return order;
    }

    /**
     * 商城购物车调起支付
     * 
     * @param orders
     * @return
     * @throws Exception 
     */
    @Transactional(rollbackFor = Throwable.class)
    public List<Order> goodsShopGo(List<Order> orders) throws Exception {
        // 订单金额
        BigDecimal shopTotal = new BigDecimal("0");
        for (Order order : orders) {
            shopTotal = shopTotal.add(order.getOrderTotal());
        }
        boolean isUpdate = false;
        List<String> ids = new ArrayList<>();
        for (Order order : orders) {
            if (StringUtil.isBlankObject(order.getShopTotal())) {
                ids.add(order.getId());
                isUpdate = true;
            }
        }
        if (isUpdate) {
            Order o = new Order();
            o.updateInit();
            o.setIds(ids);
            o.setShopTotal(shopTotal);
            int updatePartialById = orderService.updateStaticPartialByIdList(o);
            if (updatePartialById < 1) {
                ExpUtil.throwEx("设置购物车订单金额失败,请重试！");
            }
        }
        return orders;
    }

    /**
     * 获取商城订单
     * 
     * @param orderNo
     * @return
     */
    @Override
    public Order getOrderGoods(String orderNo) {
        // 查看订单是否存在
        Order findByOrderSn = orderService.getInfoByOrderSn(orderNo);
        if (StringUtil.isBlankObject(findByOrderSn)) {
            ExpUtil.throwEx("订单不存在！");
        }
        return findByOrderSn;
    }

    /**
     * 获取购物车订单
     * 
     * @param noShop
     * @return
     */
    @Override
    public List<Order> getOrderGoodsShop(String noShop) {
        // 查看订单是否存在
        List<Order> infoByNoShop = orderService.getInfoByNoShop(noShop);
        if (StringUtil.isBlankObject(infoByNoShop) || infoByNoShop.size() < 1) {
            ExpUtil.throwEx("订单不存在！");
        }
        return infoByNoShop;
    }

    /**
     * 商城支付回调
     * 
     * @param order
     * @param payNo     支付单号
     * @param payType   支付类型
     * @return
     * @throws Exception 
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean goods(Order order, String payNo, EPayType payType) throws Exception {
        // 修改订单状态
        Order ord = new Order();
        ord.updateInit();
        ord.setId(order.getId());
        ord.setPaySn(payNo);
        ord.setPayType(payType.getCode());
        ord.setIsPay(EPayStatus.YES.getCode());
        ord.setPayTime(ord.getUpdatedAt());

        if (payType == EPayType.WX) {
            ord.setPayNoWx(ord.getPaySn());
        } else if (payType == EPayType.ZFB) {
            ord.setPayNoZfb(ord.getPaySn());
        } else {
            ExpUtil.throwEx("没有这种支付方式！");
        }
        if (EOrderStatus.PAYMENT_NO.getCode() == order.getStatus()) {
            ord.setStatus(EOrderStatus.SEND_OUT_NO.getCode());
        }

        int updatePartialById = orderService.updatePartialById(ord);
        if (updatePartialById < 1) {
            ExpUtil.throwEx("订单状态修改失败！");
        }

        // 修改商品数量
        List<OrderGoods> orderGoodss = order.getOrderGoodss();
        List<GoodSpecs> arrayList = new ArrayList<>();
        for (OrderGoods orderGoods : orderGoodss) {
            GoodSpecs goodSpecs = new GoodSpecs();
            goodSpecs.updateInit();
            goodSpecs.setId(orderGoods.getSpecsId());
            goodSpecs.setStock(-orderGoods.getNum());
            arrayList.add(goodSpecs);
        }
        goodSpecsService.updateStock(arrayList);

        Map<String, String> smsParams = new HashMap<>();
        // 收货人
        smsParams.put("consignee", order.getConsignee());
        // 联系方式
        smsParams.put("number", order.getMobile());
        // 发送消息
        messageSystemService.send(
            ConstantMessageSystemTemplate.getOrder(order, orderGoodss, ConstantMessageSystemTemplate.ORDER_ORDERS),
            EMessageSystemType.ORDER.getCode(), 1, order.getId() + "", userDao.findById(order.getMerchantNo()),
            com.sojson.util.ali.AliUtil.getSmsTemplateCodeGoods(), smsParams);
        return true;
    }

    /**
     * 购物车支付回调
     * 
     * @param orders
     * @param payNo     支付单号
     * @param payType   支付类型
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean goodsShop(List<Order> orders, String payNo, EPayType payType) {
        synchronized (Lock.ORDER_STATUS) {
        }
        return true;
    }

    /**
     * 商城退款回调
     * 
     * @param orderNo   订单号
     * @param refundNo  退款单号
     * @param payType   支付类型
     * @return
     * @throws Exception 
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean goodsCancel(String orderNo, String refundNo, EPayType payType) throws Exception {
        int updatePartialById = 0;
        Order order = getOrderGoods(orderNo);

        // 查看订单是否已退款
        int code = ERefundsStatus.YES.getCode();
        if (code == order.getIsRefunds()) {
            return true;
        }

        String refundNoDb = order.getRefundSn();
        Integer closeType = order.getCloseType();
        Order ord = new Order();
        ord.setId(order.getId());
        ord.setStatus(EOrderStatus.CLOSE_YES.getCode());
        ord.setIsRefunds(code);
        // 批次退款
        if (StringUtil.isBlankObject(refundNoDb) || !refundNoDb.equals(refundNo)) {

        } else if (closeType == EOrderCloseType.CANCEL.getCode() || closeType == EOrderCloseType.REFUND.getCode()) {
            // 取消订单或者退货退款

            // 修改订单状态
            updatePartialById = orderService.updatePartialById(ord);
            if (updatePartialById < 1) {
                ExpUtil.throwEx("订单状态修改失败！");
            }

            // 修改库存
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setOrderNo(orderNo);
            List<OrderGoods> findByDto = orderGoodsService.findByDto(orderGoods);
            List<GoodSpecs> arrayList = new ArrayList<>();
            for (OrderGoods og : findByDto) {
                GoodSpecs goodSpecs = new GoodSpecs();
                goodSpecs.setId(og.getSpecsId());
                goodSpecs.setStock(og.getNum());
                arrayList.add(goodSpecs);
            }
            goodSpecsService.updateStock(arrayList);

            // 获取优惠券编号
            String couponNos = ord.getCouponNos();
            // 如果有用优惠券就将优惠券退回
            if (StringUtil.isNotBlankObject(couponNos)) {
                String[] split = couponNos.split(",");
                UserCoupon userCoupon = new UserCoupon();
                userCoupon.setNos(Arrays.asList(split));
                userCoupon.setStatus(EUserCouponStatus.USE_NO.getCode());
                userCouponDao.updateByNoList(userCoupon);
            }
            return true;
        } else if (closeType == EOrderCloseType.REIMBURSE.getCode()) {
            // 仅退款

            // 修改订单状态
            updatePartialById = orderService.updatePartialById(ord);
            if (updatePartialById < 1) {
                ExpUtil.throwEx("订单状态修改失败！");
            }
        } else {
            ExpUtil.throwEx("订单状态错误！");
        }
        if (order.getIsPay() == EPayStatus.YES.getCode()) {
            // 发送消息
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setOrderNo(order.getNo());
            List<OrderGoods> findByDto = orderGoodsService.findByDto(orderGoods);
            User findById = userDao.findById(order.getUserNo());
            if (StringUtil.isNotBlankObject(findById)) {
                // 发送消息
                messageSystemService.send(
                    ConstantMessageSystemTemplate.getOrder(order, findByDto,
                        ConstantMessageSystemTemplate.ORDER_REFUND),
                    EMessageSystemType.ORDER.getCode(), 1, order.getId() + "", findById);
            }
        }

        // 处理完成
        return true;
    }

    /**
     * 诚意金调起支付
     * 
     * @param orderId
     * @return
     * @throws Exception 
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public BaseOrder deposit(String orderId) throws Exception {
        // 查看订单是否存在
        OrderDeposit findById = orderDepositDao.findById(orderId);
        if (StringUtil.isBlankObject(findById)) {
            ExpUtil.throwEx("订单不存在！");
        }

        // 查看订单是否可以付款
        if (EOrderDepositStatus.PAYMENT_NO.getCode() != findById.getStatus()) {
            ExpUtil.throwEx("订单状态不是待付款！");
        }

        String byMap = SystemParamUtil.getStr(ConstantCache.WEB_NAME);
        findById.setBaseTitle(byMap + "应聘诚意金");
        return findById;
    }

    /**
     * 获取诚意金订单
     * 
     * @param orderNo
     * @return
     */
    @Override
    public OrderDeposit getOrderDeposit(String orderNo) {
        // 查看订单是否存在
        OrderDeposit findByOrderSn = orderDepositService.getInfoByOrderSn(orderNo);
        if (StringUtil.isBlankObject(findByOrderSn)) {
            ExpUtil.throwEx("订单不存在！");
        }
        return findByOrderSn;
    }

    /**
     * 诚意金支付回调
     * 
     * @param order
     * @param payNo     支付单号
     * @param payType   支付类型
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean deposit(OrderDeposit order, String payNo, EPayType payType) {
        // 修改订单状态
        OrderDeposit ord = new OrderDeposit();
        ord.updateInit();
        ord.setId(order.getId());
        ord.setPaySn(payNo);
        ord.setIsPay(EPayStatus.YES.getCode());
        ord.setPayType(payType.getCode());

        if (payType == EPayType.WX) {
            ord.setPayNoZfb(ord.getPaySn());
        } else if (payType == EPayType.ZFB) {
            ord.setPayNoZfb(ord.getPaySn());
        } else {
            ExpUtil.throwEx("没有这种支付方式！");
        }
        if (EOrderDepositStatus.PAYMENT_NO.getCode() == order.getStatus()) {
            ord.setStatus(EOrderDepositStatus.RETU_YES.getCode());
        }

        int updatePartialById = orderDepositService.updatePartialById(ord);
        if (updatePartialById < 1) {
            ExpUtil.throwEx("订单状态修改失败！");
        }

        // 修改用户诚意金状态
        User member = new User();
        member.setId(order.getMid());
        member.setEarnestMoneyStatus(EEarnestMoneyStatus.YES.getCode());
        member.setEarnestMoneyOrderNo(order.getOrderSn());
        int updateStock = userDao.updateById(member);
        if (updateStock < 1) {
            ExpUtil.throwEx("修改用户诚意金状态失败！");
        }

        return true;
    }

    /**
     * 诚意金退款回调
     * 
     * @param orderNo   订单号
     * @param refundNo  退款单号
     * @param payType   支付类型
     * @return
     * @throws Exception 
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean depositCancel(String orderNo, String refundNo, EPayType payType) throws Exception {
        // 获取订单
        OrderDeposit orderDeposit = getOrderDeposit(orderNo);

        // 查看订单是否已退款
        int code = ERefundsStatus.YES.getCode();
        if (code == orderDeposit.getIsRefunds()) {
            return true;
        }

        // 修改订单状态
        OrderDeposit ord = new OrderDeposit();
        ord.updateInit();
        ord.setId(orderDeposit.getId());
        ord.setIsRefunds(code);
        int updatePartialById = orderDepositService.updatePartialById(ord);
        if (updatePartialById < 1) {
            ExpUtil.throwEx("订单状态修改失败！");
        }

        // 发送消息
        messageSystemService.send(
            ConstantMessageSystemTemplate.getOrderDepositCancel(orderDeposit.getRefundTotal(), ord.getUpdatedAt()),
            EMessageSystemType.DEPOSIT_CANCEL.getCode(), null, orderNo, userDao.findById(orderDeposit.getMid()));

        // 处理完成
        return true;
    }

    /**
     * 酒店调起支付
     * 
     * @param nos
     * @return
     * @throws Exception 
     */
    @Override
    public PayResponse hotel(String[] nos) throws Exception {
        // 查看订单是否存在
        List<HotelOrder> findByNos = hotelOrderService.findByNos(nos);
        int size = findByNos.size();
        if (StringUtil.isBlankObject(findByNos) || size < 1) {
            ExpUtil.throwEx("订单不存在！");
        }
        for (HotelOrder order : findByNos) {
            if ((order.getCreatedAt().getTime() + Constant.ORDER_PAY_TIME_HOTEL) < DateUtil.nowLong()) {
                ExpUtil.throwEx("订单支付超时！");
            }
            if (EOrderStatusHotel.PAYMENT_NO.getCode() != order.getStatus()) {
                ExpUtil.throwEx("订单状态不是待付款！");
            }
        }

        PayResponse res = new PayResponse();
        // 是否是购物车支付
        if (size > 1) {
            res.setIsShop(true);
            res.setOrders(payService.hotelShopGo(findByNos));
        } else {
            res.setIsShop(false);
            res.setOrder(payService.hotelGo(findByNos.get(0)));
        }
        return res;
    }

    /**
     * 酒店调起支付
     * 
     * @param order
     * @return
     * @throws Exception 
     */
    @Transactional(rollbackFor = Throwable.class)
    public HotelOrder hotelGo(HotelOrder order) throws Exception {
        String byMap = SystemParamUtil.getStr(ConstantCache.WEB_NAME);
        order.setBaseTitle(byMap + "酒店订房");

        return order;
    }

    /**
     * 酒店购物车调起支付
     * 
     * @param orders
     * @return
     * @throws Exception 
     */
    @Transactional(rollbackFor = Throwable.class)
    public List<HotelOrder> hotelShopGo(List<HotelOrder> orders) throws Exception {
        // 订单金额
        // BigDecimal shopTotal = new BigDecimal("0");
        // for (HotelOrder order : orders) {
        // shopTotal = shopTotal.add(order.getPrice());
        // }
        // boolean isUpdate = false;
        // List<Integer> ids = new ArrayList<>();
        // for (HotelOrder order : orders) {
        // if (StringUtil.isBlankObject(order.getShopTotal())) {
        // ids.add(order.getId());
        // isUpdate = true;
        // }
        // }
        // if (isUpdate) {
        // HotelOrder o = new HotelOrder();
        // o.updateInit();
        // o.setIds(ids);
        // o.setShopTotal(shopTotal);
        // int updatePartialById = orderService.updateStaticPartialByIdList(o);
        // if (updatePartialById < 1) {
        // ExpUtil.throwEx("设置购物车订单金额失败,请重试！");
        // }
        // }
        return orders;
    }

    /**
     * 获取酒店订单
     * 
     * @param orderNo
     * @return
     */
    @Override
    public HotelOrderVo getOrderHotel(String orderNo) {
        // 查看订单是否存在
        HotelOrderVo findByNo = hotelOrderService.getInfo(orderNo);
        if (StringUtil.isBlankObject(findByNo)) {
            ExpUtil.throwEx("订单不存在！");
        }
        return findByNo;
    }

    /**
     * 酒店支付回调
     * 
     * @param order
     * @param payNo     支付单号
     * @param payType   支付类型
     * @return
     * @throws Exception 
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean hotel(HotelOrderVo order, String payNo, EPayType payType) throws Exception {
        // 修改订单状态
        HotelOrder ord = new HotelOrder();
        ord.updateInit();
        ord.setId(order.getId());
        ord.setNoPay(payNo);
        ord.setIsPay(EPayStatus.YES.getCode());
        ord.setPayType(payType.getCode());
        ord.setStatus(EOrderStatusHotel.CHECK_NO.getCode());
        ord.setIsCheck(EGeneralYesNo.YES.getCode());

        if (payType == EPayType.WX) {
            ord.setNoPayWx(ord.getNoPay());
        } else if (payType == EPayType.ZFB) {
            ord.setNoPayZfb(ord.getNoPay());
        } else {
            ExpUtil.throwEx("没有这种支付方式！");
        }

        int updatePartialById = hotelOrderService.updateById(ord);
        if (updatePartialById < 1) {
            ExpUtil.throwEx("订单状态修改失败！");
        }

        HotelOrderRoom hotelOrderRoom = order.getHotelOrderRoom();
        if (StringUtil.isNotBlankObject(hotelOrderRoom)) {
            User findById = userDao.findById(order.getNoUser());
            if (StringUtil.isBlankObject(findById)) {
                return true;
            }
            // 发送消息
            Map<String, String> smsParams = new HashMap<>();
            // 姓名
            smsParams.put("name", findById.getName());
            // 手机号
            smsParams.put("number", findById.getMobile());
            // 酒店名称
            smsParams.put("hotelnumber", hotelOrderRoom != null ? hotelOrderRoom.getNameHotel() : "null");
            messageSystemService.send(
                ConstantMessageSystemTemplate.getOrder(order, hotelOrderRoom,
                    ConstantMessageSystemTemplate.ORDER_ORDERS),
                EMessageSystemType.ORDER.getCode(), Integer.parseInt(EModuleNo.HOTEL.getCode()), order.getNo(),
                userDao.findById(order.getNoMerchant()), com.sojson.util.ali.AliUtil.getSmsTemplateCodeHotel(),
                smsParams);
        }
        return true;
    }

    /**
     * 酒店订单退款回调
     * 
     * @param orderNo   订单号
     * @param refundNo  退款单号
     * @param payType   支付类型
     * @return
     * @throws Exception 
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean hotelCancel(String orderNo, String refundNo, EPayType payType) throws Exception {
        // 获取订单
        HotelOrder order = getOrderHotel(orderNo);

        // 查看订单是否已退款
        int code = ERefundsStatus.YES.getCode();
        if (code == order.getIsRefunds()) {
            return true;
        }
        int updateByNo = 0;

        Integer closeType = order.getCloseType();
        HotelOrder ord = new HotelOrder();
        ord.setNo(order.getNo());
        ord.setStatus(EOrderStatusHotel.CLOSE_YES.getCode());
        ord.setIsRefunds(code);
        // 取消订单
        if (closeType == EOrderHotelCloseType.CANCEL.getCode()) {
            // 修改订单状态
            updateByNo = hotelOrderService.updateByNo(ord);
            if (updateByNo < 1) {
                ExpUtil.throwEx("订单状态修改失败！");
            }

            // 获取优惠券编号
            String couponNos = ord.getNosCoupon();
            // 如果有用优惠券就将优惠券退回
            if (StringUtil.isNotBlankObject(couponNos)) {
                String[] split = couponNos.split(",");
                UserCoupon userCoupon = new UserCoupon();
                userCoupon.setNos(Arrays.asList(split));
                userCoupon.setStatus(EUserCouponStatus.USE_NO.getCode());
                userCouponDao.updateByNoList(userCoupon);
            }
            return true;
        } else if (closeType == EOrderHotelCloseType.REIMBURSE.getCode()) {
            // 仅退款

            // 修改订单状态
            updateByNo = hotelOrderService.updateByNo(ord);
            if (updateByNo < 1) {
                ExpUtil.throwEx("订单状态修改失败！");
            }
        } else {
            ExpUtil.throwEx("订单状态错误！");
        }
        if (order.getIsPay() == EPayStatus.YES.getCode()) {
            // 发送消息
            HotelOrderRoom findByNoHotelOrder = hotelOrderRoomService.findByNoHotelOrder(order.getNo());
            User findById = userDao.findById(order.getNoUser());
            // 发送消息
            messageSystemService.send(
                ConstantMessageSystemTemplate.getOrder(order, findByNoHotelOrder,
                    ConstantMessageSystemTemplate.ORDER_REFUND),
                EMessageSystemType.ORDER.getCode(), 1, order.getNo(), findById);
        }

        // 处理完成
        return true;
    }

    /**
     * 提现
     * 
     * @param transferRecord
     * @return
     * @throws Exception
     */
    @Override
    public int withdrawDeposit(TransferRecord transferRecord) throws Exception {
        synchronized (Lock.BALANCE_LOG) {
            // 提现
            WithdrawDepositVo withdrawDeposit = payService.withdrawDepositGo(transferRecord, false);
            // 处理结束
            if (StringUtil.isBlankObject(withdrawDeposit)) {
                return 1;
            }
            TransferRecord tr = withdrawDeposit.getTransferRecord();

            // 获取结果
            // 支付结果
            Status status = withdrawDeposit.getStatus();
            // 支付单号
            tr.setPayNo(withdrawDeposit.getNoPay());
            // 处理结果
            return payService.withdrawDepositEnd(tr, status);
        }
    }

    /**
     * 提现
     */
    @Transactional(rollbackFor = Throwable.class)
    public WithdrawDepositVo withdrawDepositGo(TransferRecord transferRecord, boolean isAudit) throws Exception {
        // 获取提现订单
        WithdrawDepositVo withdrawDeposit = payService.withdrawDepositInit(transferRecord, isAudit);
        TransferRecord tr = withdrawDeposit.getTransferRecord();

        // 提现
        return payService.WithdrawDepositStart(tr);
    }

    /**
     * 提现申请
     * 
     * @param transferRecord
     * @return
     * @throws Exception
     */
    @Override
    public int withdrawDepositApplyFor(TransferRecord transferRecord) throws Exception {
        return payService.withdrawDepositInit(transferRecord, true) == null ? 0 : 1;
    }

    /**
     * 添加转账记录
     * 
     * @param transferRecord
     * @param isAudit           是否需要审核(如果需要就将状态设为待审核,不需要就将状态设为处理中或成功)
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Throwable.class)
    public WithdrawDepositVo withdrawDepositInit(TransferRecord transferRecord, boolean isAudit) throws Exception {
        // 获取提现订单
        WithdrawDepositVo withdrawDeposit = payService.withdrawDeposit(transferRecord, isAudit);

        // 处理其他内容
        payService.withdrawDepositManage(withdrawDeposit);
        return withdrawDeposit;
    }

    /**
     * 添加转账记录
     * 
     * @param transferRecord
     * @param isAudit           是否需要审核(如果需要就将状态设为待审核,不需要就将状态设为处理中或成功)
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Throwable.class)
    public WithdrawDepositVo withdrawDeposit(TransferRecord transferRecord, boolean isAudit) throws Exception {
        WithdrawDepositVo withdrawDepositVo = new WithdrawDepositVo();
        TransferRecord tr = new TransferRecord();
        tr.insertInit();
        BigDecimal total = transferRecord.getTotal();
        String uuid = IdUtil.uuid();
        Integer payType = transferRecord.getPayType();
        Integer type = transferRecord.getType();

        // 获取提现用户的信息
        User findById = userDao.findById(TokenUtil.getUserId());
        if (type == ETransferRecordType.BALANCE.getCode()) {
            BigDecimal balance = findById.getBalance();
            if (ArithUtil.subBig(balance, total).doubleValue() < 0) {
                ExpUtil.throwEx("余额不足！");
            }
        } else if (type == ETransferRecordType.BROKERAGE.getCode()) {
            BigDecimal brokerage = findById.getBrokerage();
            if (ArithUtil.subBig(brokerage, total).doubleValue() < 0) {
                ExpUtil.throwEx("余额不足！");
            }
        }
        // 设置提现类型
        if (payType == EPayType.WX.getCode()) {
            String openid = findById.getOpenid();
            if (StringUtil.isBlank(openid)) {
                ExpUtil.throwEx("请先绑定微信！");
            }
            tr.setWxOpenid(openid);
        } else if (payType == EPayType.ZFB.getCode()) {
            String openid = findById.getOpenidZfb();
            if (StringUtil.isBlank(openid)) {
                ExpUtil.throwEx("请先绑定支付宝！");
            }
            tr.setZfbOpenid(openid);
        } else if (payType == EPayType.OFFLINE.getCode()) {
        } else {
            ExpUtil.throwEx("没有这种支付方式！");
        }

        // 添加转账记录
        tr.setTitle("提现");
        tr.setPayType(payType);
        tr.setBank(transferRecord.getBank());
        tr.setNoBank(transferRecord.getNoBank());
        tr.setNameUserBank(transferRecord.getNameUserBank());
        tr.setOrderNo(uuid);
        tr.setUserId(findById.getId());
        tr.setUsername(findById.getUsername());
        tr.setMobile(findById.getMobile());
        tr.setName(findById.getName());
        tr.setType(transferRecord.getType());
        tr.setTotal(total);
        // 如果需要审核就将状态改为审核中,否则修改为处理中或成功(线下提现直接成功)
        tr.setStatus(isAudit ? ETransferRecordStatus.AUDIT_ING.getCode() : payType != EPayType.OFFLINE.getCode()
            ? ETransferRecordStatus.LOADING.getCode() : ETransferRecordStatus.SECCUSS.getCode());
        int insert = transferRecordDao.insert(tr);
        if (insert < 1) {
            ExpUtil.throwEx("添加转账记录失败");
        }

        // 返回转账记录和用户信息
        withdrawDepositVo.setTransferRecord(tr);
        withdrawDepositVo.setUser(findById);
        return withdrawDepositVo;
    }

    /**
     * 计算并修改用户当前佣金
     * 
     * @param withdrawDeposit
     * @throws Exception
     */
    @Transactional(rollbackFor = Throwable.class)
    public void withdrawDepositManage(WithdrawDepositVo withdrawDeposit) throws Exception {
        TransferRecord tr = withdrawDeposit.getTransferRecord();
        User user = withdrawDeposit.getUser();
        BigDecimal total = tr.getTotal();
        String orderNo = tr.getOrderNo();
        Integer payType = tr.getPayType();

        String msg = null;
        if (payType == EPayType.WX.getCode()) {
            msg = "提现至微信";
        } else if (payType == EPayType.ZFB.getCode()) {
            msg = "提现至支付宝";
        } else if (payType == EPayType.OFFLINE.getCode()) {
            msg = "线下转账";
        }

        // 修改佣金金额,添加佣金记录,发送提现消息
        User mem = new User();
        mem.setId(user.getId());
        BalanceLog balanceLog = new BalanceLog();
        MessageSystem messageSystem = null;

        Integer type = tr.getType();
        if (type == ETransferRecordType.BALANCE.getCode()) {
            mem.setBalance(user.getBalance().subtract(total));
            mem.setBalanceWithdrawWx(user.getBalanceWithdrawWx().add(total));

            balanceLog.insertInit("佣金" + msg, user.getId(), total, user.getBalance(),
                EBalanceType.WITHDRAW_WX.getCode(), null, EBalanceTotalType.COMMISSION.getCode(),
                EBalanceCount.REDUCE.getCode(), orderNo, orderNo + "-佣金提现");

            messageSystem = ConstantMessageSystemTemplate.getBalanceApplyWithdrawDeposit(total);
        } else if (type == ETransferRecordType.BROKERAGE.getCode()) {
            mem.setBrokerage(user.getBrokerage().subtract(total));
            mem.setBrokerageWithdraw(user.getBrokerageWithdraw().add(total));

            balanceLog.insertInit("余额" + msg, user.getId(), total, user.getBrokerage(),
                EBalanceType.WITHDRAW_WX.getCode(), null, EBalanceTotalType.COMMISSION.getCode(),
                EBalanceCount.REDUCE.getCode(), orderNo, orderNo + "-余额提现");
            messageSystem = ConstantMessageSystemTemplate.getBrokerageApplyWithdrawDeposit(total);
        } else {
            ExpUtil.throwEx("类型不存在！");
        }
        int updatePartialById = userDao.updateById(mem);
        if (updatePartialById < 1) {
            ExpUtil.throwEx("修改金额失败！");
        }
        // 添加佣金记录
        int insert = balanceLogService.insert(balanceLog);
        if (insert < 1) {
            ExpUtil.throwEx("添加佣金记录失败");
        }
        // 添加佣金记录
        messageSystemService.send(messageSystem, EMessageSystemType.BROKERAGE.getCode(), null, orderNo, user);
    }

    /**
     * 计算并修改用户当前佣金(审核不通过,回滚)
     * 
     * @param transferRecord
     * @throws Exception
     */
    @Transactional(rollbackFor = Throwable.class)
    public void withdrawDepositManageRollBack(TransferRecord transferRecord) throws Exception {
        User user = userDao.findById(transferRecord.getUserId());
        if (StringUtil.isBlankObject(user)) {
            ExpUtil.throwEx("用户不存在！");
        }
        BigDecimal total = transferRecord.getTotal();
        String orderNo = transferRecord.getOrderNo();
        Integer payType = transferRecord.getPayType();

        String msg = null;
        if (payType == EPayType.WX.getCode()) {
            msg = "提现至微信审核不通过";
        } else if (payType == EPayType.ZFB.getCode()) {
            msg = "提现至支付宝审核不通过";
        } else if (payType == EPayType.OFFLINE.getCode()) {
            msg = "线下转账审核不通过";
        }

        // 修改佣金金额,添加佣金记录,发送提现消息
        User mem = new User();
        mem.setId(user.getId());
        BalanceLog balanceLog = new BalanceLog();
        MessageSystem messageSystem = null;

        Integer type = transferRecord.getType();
        if (type == ETransferRecordType.BALANCE.getCode()) {
            mem.setBalance(user.getBalance().add(total));
            mem.setBalanceWithdrawWx(user.getBalanceWithdrawWx().subtract(total));

            balanceLog.insertInit("佣金" + msg, user.getId(), total, user.getBalance(),
                EBalanceType.WITHDRAW_WX.getCode(), null, EBalanceTotalType.COMMISSION.getCode(),
                EBalanceCount.ADD.getCode(), orderNo, orderNo + "-佣金提现");

            messageSystem = ConstantMessageSystemTemplate.getBalanceApplyWithdrawDepositAuditFail(total);
        } else if (type == ETransferRecordType.BROKERAGE.getCode()) {
            mem.setBrokerage(user.getBrokerage().add(total));
            mem.setBrokerageWithdraw(user.getBrokerageWithdraw().subtract(total));

            balanceLog.insertInit("余额" + msg, user.getId(), total, user.getBrokerage(),
                EBalanceType.WITHDRAW_WX.getCode(), null, EBalanceTotalType.COMMISSION.getCode(),
                EBalanceCount.ADD.getCode(), orderNo, orderNo + "-余额提现");
            messageSystem = ConstantMessageSystemTemplate.getBrokerageApplyWithdrawDepositAuditFail(total);
        } else {
            ExpUtil.throwEx("类型不存在！");
        }
        int updatePartialById = userDao.updateById(mem);
        if (updatePartialById < 1) {
            ExpUtil.throwEx("修改金额失败！");
        }

        // 添加佣金记录
        int insert = balanceLogService.insert(balanceLog);
        if (insert < 1) {
            ExpUtil.throwEx("添加佣金记录失败");
        }

        // 修改订单状态
        int updatePartialByOrderNo = transferRecordDao.updatePartialByOrderNo(transferRecord);
        if (updatePartialByOrderNo < 1) {
            ExpUtil.throwEx("修改订单状态失败！");
        }

        // 添加佣金记录
        messageSystemService.send(messageSystem, EMessageSystemType.BROKERAGE.getCode(), null, orderNo, user);
    }

    /**
     * 提现审核
     * 
     * @param transferRecord
     * @return
     * @throws Exception
     */
    @Override
    public int withdrawDepositAudit(TransferRecord transferRecord) throws Exception {
        synchronized (Lock.BALANCE_LOG) {
            // 获取订单
            TransferRecord tr = payService.withdrawDepositAuditGo(transferRecord);
            if (StringUtil.isBlankObject(tr)) {
                return 1;
            }

            // 提现
            return payService.withdrawDepositGo(tr);
        }
    }

    /**
     * 提现审核
     * 
     * @param transferRecord
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Throwable.class)
    public TransferRecord withdrawDepositAuditGo(TransferRecord transferRecord) throws Exception {
        // 获取订单
        String orderNo = transferRecord.getOrderNo();
        TransferRecord tr = transferRecordDao.findByOrderNo(orderNo);

        // 判断订单是否可操作
        if (StringUtil.isBlankObject(tr)) {
            ExpUtil.throwEx("订单不存在！");
        }
        if (tr.getStatus() != ETransferRecordStatus.AUDIT_ING.getCode()) {
            ExpUtil.throwEx("订单状态不是审核中！");
        }

        // 审核不通过
        Integer status = transferRecord.getStatus();
        if (status == ETransferRecordStatus.AUDIT_NO.getCode()) {
            tr.setStatus(status);
            tr.setMessage(transferRecord.getMessage());
            payService.withdrawDepositManageRollBack(tr);
            return null;
        }

        // 修改订单状态
        tr.setStatus(tr.getPayType() != EPayType.OFFLINE.getCode() ? ETransferRecordStatus.LOADING.getCode()
            : ETransferRecordStatus.SECCUSS.getCode());
        return tr;
    }

    public int withdrawDepositGo(TransferRecord tr) throws Exception {
        WithdrawDepositVo withdrawDeposit = payService.withdrawDepositGoTwo(tr);
        // 处理结束
        if (StringUtil.isBlankObject(withdrawDeposit)) {
            return 1;
        }

        // 获取结果
        // 支付结果
        Status status = withdrawDeposit.getStatus();
        // 支付单号
        tr.setPayNo(withdrawDeposit.getNoPay());
        // 处理结果
        return payService.withdrawDepositEnd(tr, status);
    }

    @Transactional(rollbackFor = Throwable.class)
    public WithdrawDepositVo withdrawDepositGoTwo(TransferRecord tr) throws Exception {
        int updatePartialByOrderNo = transferRecordDao.updatePartialByOrderNo(tr);
        if (updatePartialByOrderNo < 1) {
            ExpUtil.throwEx("修改转账记录失败");
        }

        return payService.WithdrawDepositStart(tr);
    }

    /**
     * 提现成功
     * 
     * @param transferRecord
     * @param noPay             支付单号
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int withdrawDepositSuccess(TransferRecord transferRecord, String noPay) throws Exception {
        transferRecord.setStatus(ETransferRecordStatus.SECCUSS.getCode());
        transferRecord.setSuccessTime(DateUtil.nowDate());
        transferRecord.setPayNo(noPay);
        int updatePartialById = transferRecordDao.updatePartialById(transferRecord);
        return updatePartialById;
    }

    /**
     * 提现中
     * 
     * @param transferRecord
     * @param noPay             支付单号
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int withdrawDepositIng(TransferRecord transferRecord, String noPay) throws Exception {
        transferRecord.setStatus(ETransferRecordStatus.LOADING.getCode());
        transferRecord.setPayNo(noPay);
        int updatePartialById = transferRecordDao.updatePartialById(transferRecord);
        return updatePartialById;
    }

    /**
     * 提现失败
     * 
     * @param transferRecord
     * @param msg               失败信息
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int withdrawDepositFail(TransferRecord transferRecord, String msg) throws Exception {
        transferRecord.setStatus(ETransferRecordStatus.FAIL.getCode());
        transferRecord.setMessage(msg);
        return transferRecordDao.updatePartialById(transferRecord);
    }

    /**
     * 重新提现
     * 
     * @param orderNo   订单号
     * @return
     * @throws Exception
     */
    @Override
    public int anewWithdrawDeposit(String orderNo) throws Exception {
        // 获取订单
        TransferRecord tr = payService.anewWithdrawDepositGo(orderNo);

        // 提现
        WithdrawDepositVo withdrawDeposit = payService.WithdrawDepositStart(tr);
        // 处理中(没处理完)
        if (StringUtil.isBlankObject(withdrawDeposit)) {
            return 1;
        }

        // 获取结果
        // 支付结果
        Status status = withdrawDeposit.getStatus();
        // 支付单号
        tr.setPayNo(withdrawDeposit.getNoPay());
        // 处理结果
        return payService.withdrawDepositEnd(tr, status);
    }

    public TransferRecord anewWithdrawDepositGo(String orderNo) throws Exception {
        TransferRecord findByOrderNo = transferRecordDao.findByOrderNo(orderNo);
        if (StringUtil.isBlankObject(findByOrderNo)) {
            ExpUtil.throwEx("订单不存在！");
        }
        Integer status = findByOrderNo.getStatus();
        if (ETransferRecordStatus.FAIL.getCode() != status && ETransferRecordStatus.LOADING.getCode() != status) {
            ExpUtil.throwEx("提现失败才能重新提现！");
        }

        Integer payType = findByOrderNo.getPayType();
        TransferRecord t = new TransferRecord();
        t.setId(findByOrderNo.getId());
        User findById = userDao.findById(findByOrderNo.getUserId());
        String openidTra = null;
        String openidMem = null;
        if (payType == EPayType.WX.getCode()) {
            openidTra = findByOrderNo.getWxOpenid();
            openidMem = findById.getOpenid();
            t.setWxOpenid(openidMem);
            findByOrderNo.setWxOpenid(openidMem);
        } else if (payType == EPayType.ZFB.getCode()) {
            openidTra = findByOrderNo.getZfbOpenid();
            openidMem = findById.getOpenidZfb();
            t.setZfbOpenid(openidMem);
            findByOrderNo.setZfbOpenid(openidMem);
        } else if (payType == EPayType.OFFLINE.getCode()) {
            openidTra = findByOrderNo.getMobile();
            openidMem = findById.getMobile();
            t.setMobile(openidMem);
            findByOrderNo.setMobile(openidMem);
        } else {
            ExpUtil.throwEx("没有这种支付方式！");
        }

        if (!openidMem.equals(openidTra)) {
            int updatePartialById = transferRecordDao.updatePartialById(t);
            if (updatePartialById < 1) {
                ExpUtil.throwEx("修改订单数据失败，请重试！");
            }
        }
        return findByOrderNo;
    }

    /**
     * 提现(如果返回null就表示后面不需要处理)
     * 
     * @param tr
     * @return
     * @throws Exception
     */
    public WithdrawDepositVo WithdrawDepositStart(TransferRecord tr) throws Exception {
        WithdrawDepositVo withdrawDeposit = new WithdrawDepositVo();
        Status status = null;
        String noPay = null;
        String byMap = SystemParamUtil.getStr(ConstantCache.WEB_NAME);
        String title = byMap + tr.getTitle();
        Integer payType = tr.getPayType();

        // 提现
        if (payType == EPayType.WX.getCode()) {
            WxResponseV2 response =
                WxPayUtil.withdrawDeposit(tr.getOrderNo(), tr.getTotal(), tr.getWxOpenid(), null, title);
            status = WxPayUtil.getStatus(response);
            noPay = response.getPaymentNo();
        } else if (payType == EPayType.ZFB.getCode()) {
            // 提现
            AlipayFundTransUniTransferResponse res =
                AliUtil.withdrawDeposit(tr.getOrderNo(), tr.getTotal(), tr.getZfbOpenid(), null, title);
            status = AliUtil.getStatusFundTrans(res);
            noPay = res.getOrderId();
        } else if (payType == EPayType.OFFLINE.getCode()) {

            // 发送提现到账消息
            Date nowDate = DateUtil.nowDate();
            MessageSystem messageSystem = null;
            if (tr.getType() == ETransferRecordType.BALANCE.getCode()) {
                messageSystem = ConstantMessageSystemTemplate.getBalanceAccount(tr.getTotal(), nowDate);
            } else if (tr.getType() == ETransferRecordType.BROKERAGE.getCode()) {
                messageSystem = ConstantMessageSystemTemplate.getBrokerageAccount(tr.getTotal(), nowDate);
            }
            messageSystemService.send(messageSystem, EMessageSystemType.BROKERAGE.getCode(), null, tr.getOrderNo(),
                userDao.findById(tr.getUserId()));
            return null;
        } else {
            ExpUtil.throwEx("没有这种支付方式！");
        }

        withdrawDeposit.setStatus(status);
        withdrawDeposit.setNoPay(noPay);
        return withdrawDeposit;
    }

    /**
     * 提现结束
     * 
     * @param tr
     * @param status
     * @return
     * @throws Exception
     */
    public int withdrawDepositEnd(TransferRecord tr, Status status) throws Exception {
        // 处理结果
        TransferRecord tran = new TransferRecord();
        tran.updateInit();
        tran.setId(tr.getId());
        // 提现失败
        if (status.isFail()) {
            // 如果不需要处理就直接抛异常
            if (!status.getIsDispose()) {
                ExpUtil.throwEx(status.getMsg());
            }
            payService.withdrawDepositFail(tran, status.getMsg());
            ExpUtil.throwEx(status.getMsg());
            return 0;
        } else if (status.isIng()) {
            return payService.withdrawDepositIng(tran, tr.getPayNo());
        } else if (status.isSuccess()) {
            // 提现成功
            int withdrawDepositSuccess = payService.withdrawDepositSuccess(tran, tr.getPayNo());

            // 发送提现到账消息
            Date nowDate = DateUtil.nowDate();
            MessageSystem messageSystem = null;
            if (tr.getType() == ETransferRecordType.BALANCE.getCode()) {
                messageSystem = ConstantMessageSystemTemplate.getBalanceAccount(tr.getTotal(), nowDate);
            } else if (tr.getType() == ETransferRecordType.BROKERAGE.getCode()) {
                messageSystem = ConstantMessageSystemTemplate.getBrokerageAccount(tr.getTotal(), nowDate);
            }
            messageSystemService.send(messageSystem, EMessageSystemType.BROKERAGE.getCode(), null, tr.getOrderNo(),
                userDao.findById(tr.getUserId()));
            return withdrawDepositSuccess;
        } else {
            ExpUtil.throwEx("体现状态错误");
            return 0;
        }
    }

}